/*
 * main.h
 *
 *  Created on: 2021-12-09
 *      Author: chenss
 */

#ifndef INC_MAIN_H_
#define INC_MAIN_H_

#include "NuMicro.h"

#ifdef __cplusplus
#   define BEGIN_C_DECLS extern "C" {
#   define END_C_DECLS }
#else
#   define BEGIN_C_DECLS
#   define END_C_DECLS
#endif

BEGIN_C_DECLS

//#define CMSIS_OS 2
#define ARM_MATH_CM4

#include <stdbool.h>
#include <string.h>
#include <stdio.h>

#ifdef CMSIS_OS
#   include "cmsis_os.h"
#endif

#include "stream/stream.h"
#include "stream/chprintf.h"

#define NVIC_PRIORITY_GROUP 4

#ifndef FALSE
#   define FALSE false
#endif

#ifndef TRUE
#   define TRUE true
#endif

extern int mprintf(const char *fmt, ...);
extern int nbprintf(const char *fmt, ...);

#ifdef CMSIS_OS
static inline uint32_t __OsEnterCritical(void)
{
    if(__get_IPSR() != 0U)
    {
        return taskENTER_CRITICAL_FROM_ISR();
    }
    else
    {
        taskENTER_CRITICAL();
        return 0;
    }
}

static inline void __OsExitCritical(uint32_t mask)
{
    if(__get_IPSR() != 0U)
    {
        taskEXIT_CRITICAL_FROM_ISR(mask);
    }
    else
    {
        taskEXIT_CRITICAL();
    }
}

#   define OS_ENTER_CRITICAL() uint32_t __osMask = __OsEnterCritical()
#   define OS_EXIT_CRITICAL()  __OsExitCritical(__osMask)
#else
#   define OS_ENTER_CRITICAL() ENTER_CRITICAL()
#   define OS_EXIT_CRITICAL()  EXIT_CRITICAL()
#endif // CMSIS_OS

static inline uint32_t __EnterCritical(void)
{
    uint32_t primask = __get_PRIMASK();

    __disable_irq();
    return primask;
}

static inline void __ExitCritical(uint32_t primask)
{
    __set_PRIMASK(primask);
}

#define ENTER_CRITICAL() {uint32_t __primask = __EnterCritical()
#define EXIT_CRITICAL()  __ExitCritical(__primask);}

#ifdef __DEBUG__
#   define debug(fmt, args...) printf(fmt, ##args)
#   define vdebug(fmt, vargs)  vprintf(fmt, vargs)
#   define mdebug(fmt, args...) mprintf(fmt, ##args)
#   define nbdebug(fmt, args...) nbprintf(fmt, ##args)
#   define ON_DEBUG(foo) foo
#   define ON_RELEASE(foo)
#   define IDLE() __WFI()
#   define __DEBUG_BKPT()  asm volatile ("bkpt 0")
# define assert(expr) ((expr) ? (void)0 : assert_failed(__FILE__, __LINE__))
void assert_failed(const char *file, uint32_t line);
#else
#   define debug(...)
#   define vdebug(fmt, vargs)
#   define mdebug(fmt, vargs...)
#   define nbdebug(fmt, args...)
#   define ON_DEBUG(foo)
#   define ON_RELEASE(foo) foo
#   define IDLE() __WFI()
#   define __DEBUG_BKPT()
#   define assert(e)
#endif

#ifndef UNUSED
#   define UNUSED(x) (void) x
#endif

#ifndef assert_param
#   define assert_param assert
#endif

#ifndef __WEAK
#   define __WEAK   __attribute__((weak))
#endif

#ifndef MAX
#	define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#	define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

#define CONSTRAIN(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))

#define TO_STRING(sym) #sym
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define BIT_SET(reg, bit) (reg) |= (bit)
#define BIT_CLR(reg, bit) (reg) &= ~ (bit)
#define BITS_SET(reg, mask, bits) reg = (reg & (~(mask))) | (bits)
#define BIT_MASK(n) (0x01 << (n))

#define _PORT(p, n) P ## p
#define _BIT(P, n)  BIT ## n
#define _PIN(p, n)  P ## p ## n
#define PORT(io)    (_PORT(io))
#define BIT(io)     (_BIT(io))
#define PIN(io)     (_PIN(io))

#define READ_SAFELY(v, from) do{v = from;}while(v != from)

#define __optimize(o) __attribute__((optimize(o)))

typedef int (*Callback_t)(void *arg);

typedef struct
{
    Callback_t callback;
    void *arg;
} Callback_Info_t;

void HAL_Delay(uint32_t ms);
uint64_t HAL_GetTick(void);
void Power_Off(void);
void Power_On(void);
void Main_StopRunLed(void);

static inline void HAL_Reset(void)
{
    SYS_UnlockReg();
    SYS_ResetChip();
    SYS_LockReg();
}

__STATIC_INLINE void Main_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)
{
    uint32_t priority = NVIC_EncodePriority(NVIC_PRIORITY_GROUP, PreemptPriority, SubPriority);

    NVIC_SetPriority(IRQn, priority);
}

typedef struct FixPoint
{
    int value; // 放大后的数值
    int times; // 放大倍数
}FixPoint_t;

static inline float FixPoint2Float(const FixPoint_t *fxp)
{
    return (float)(fxp->value) / (float)(fxp->times);
}

#if 0
static inline void Float2FixPoint(float f, FixPoint_t *fxp, int times)
{
    fxp->times = times;
    fxp->value = roundf(f * times);
}
#endif

END_C_DECLS
#endif /* INC_MAIN_H_ */
